package design.donkey.auto.ddl;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.ServiceLoader;

import javax.sql.DataSource;

import design.donkey.auto.ddl.analysis.AnnotationAnalysis;
import design.donkey.auto.ddl.analysis.JpaAnnotationAnalysis;
import design.donkey.auto.ddl.analysis.MyBatisPlusAnnotationAnalysis;
import design.donkey.auto.ddl.dialect.DefaultDialect;
import design.donkey.auto.ddl.dialect.Dialect;
import design.donkey.auto.ddl.util.AutoDdlCommonUtils;
import design.donkey.framework.common.util.CommonUtils;
import lombok.extern.slf4j.Slf4j;

/**
 * AutoDdl 构建
 *
 * @author zhangjiakung
 * @since 1.0.0
 */
@Slf4j
public class AutoDdlFactory {

    private static final String JPA_CLASS_NAME = "jakarta.persistence.Table";
    private static final String MYBATIS_CLASS_NAME = "com.baomidou.mybatisplus.annotation.TableName";

    /**
     * 实例化
     *
     * @param dataSource 数据源
     * @param format 是否格式化
     * @param out 是否输出
     */
    public static AutoDdl factory(DataSource dataSource, boolean format, boolean out) {
        return factory(dataSource, AutoDdlType.NONE, format, out);
    }

    /**
     * 实例化
     *
     * @param dataSource 数据源
     * @param autoDdlType 操作类型
     * @param format 是否格式化
     * @param out 是否输出
     */
    public static AutoDdl factory(DataSource dataSource, AutoDdlType autoDdlType, boolean format, boolean out) {
        // 获取解析器
        AnnotationAnalysis annotationAnalysis = autoAnnotationAnalysis();

        // 获取方言
        Dialect dialect = dialectSpi(dataSource);

        // 实例化自动 DDL
        return new AutoDdl(autoDdlType, dialect, annotationAnalysis, format, out);
    }

    /**
     * 通过 SPI 机制获取 数据库方言
     * 
     * @param dataSource 数据源
     * @return 方言
     */
    public static Dialect dialectSpi(DataSource dataSource) {
        ServiceLoader<Dialect> serviceLoader = ServiceLoader.load(Dialect.class);

        try (Connection connection = dataSource.getConnection()) {
            DatabaseMetaData metaData = connection.getMetaData();
            String databaseProductName = metaData.getDatabaseProductName();
            String databaseProductVersion = metaData.getDatabaseProductVersion();
            for (Dialect dialect : serviceLoader) {
                if (CommonUtils.equalsIgnoreCase(databaseProductName, dialect.getProductName())
                    && databaseProductVersion.startsWith(dialect.getProductVersion())) {
                    serviceLoader.reload();
                    return dialect;
                }
            }
            log.warn("没有对应的 {} - {}数据库方言，使用默认方言", databaseProductName, databaseProductVersion);
            return new DefaultDialect();
        } catch (SQLException e) {
            log.error("获取数据库方言失败，使用默认方言", e);
            return new DefaultDialect();
        }
    }

    /**
     * 自动获取注解解析器
     * 
     * @return 注解解析器
     */
    public static AnnotationAnalysis autoAnnotationAnalysis() {
        if (AutoDdlCommonUtils.existClass(JPA_CLASS_NAME)) {
            return new JpaAnnotationAnalysis();
        } else if (AutoDdlCommonUtils.existClass(MYBATIS_CLASS_NAME)) {
            return new MyBatisPlusAnnotationAnalysis();
        } else {
            return new AnnotationAnalysis();
        }
    }

    private AutoDdlFactory() {}
}
